package com.dabai.iot.core.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.dabai.common.core.utils.DateUtils;
import com.dabai.iot.common.constant.IotKeyConstant;
import com.dabai.iot.common.enums.BizLogCode;
import com.dabai.iot.common.enums.BizLogType;
import com.dabai.iot.common.model.DeviceInfo;
import com.dabai.iot.common.model.IotMqttMessage;
import com.dabai.iot.core.dto.CustomMessageInput;
import com.dabai.iot.core.dto.PropertyMessageInput;
import com.dabai.iot.core.entity.DeviceEntity;
import com.dabai.iot.core.entity.ThingModelBlockEntity;
import com.dabai.iot.core.entity.ThingModelItemEntity;
import com.dabai.iot.core.service.IDeviceLogService;
import com.dabai.iot.core.service.IMessageService;
import com.dabai.iot.core.service.IThingModelBlockService;
import com.dabai.iot.core.service.IThingModelItemService;
import com.dabai.iot.mqtt.api.RemoteMqttService;
import com.dabai.iot.mqtt.topics.SysTopics;
import io.netty.handler.codec.mqtt.MqttQoS;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 消息服务实现类
 *
 * @author kev1n
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageServiceImpl implements IMessageService {

    private final IDeviceLogService deviceLogService;
    private final IThingModelBlockService thingModelBlockService;
    private final IThingModelItemService thingModelItemService;

    @DubboReference
    private final RemoteMqttService remoteMqttService;

    /**
     * 发送自定义消息到设备
     */
    @Override
    public void sendCustomMessage(DeviceEntity device, CustomMessageInput message) {
        String traceId = IdWorker.get32UUID();
        Date nowDate = DateUtils.getNowDate();
        sendMessage(device, traceId, message.getTopic(), message.getMessage(), nowDate);
    }

    /**
     * 发送属性消息到设备
     */
    @Override
    public void sendPropertyMessage(DeviceEntity device, PropertyMessageInput message) {
        Long blockId = message.getBlockId();
        ThingModelBlockEntity modelBlock = thingModelBlockService.getById(blockId);
        if (modelBlock == null) {
            return;
        }

        JSONObject blockJson = new JSONObject();
        blockJson.put(IotKeyConstant.BLOCK_ID, modelBlock.getBlockIdentifier());

        JSONObject properties = new JSONObject();
        for (PropertyMessageInput.ItemParam itemParam : message.getItemParams()) {
            Long itemId = itemParam.getItemId();
            ThingModelItemEntity modelItem = thingModelItemService.getById(itemId);
            properties.put(modelItem.getIdentifier(), itemParam.getValue());
        }
        blockJson.put(IotKeyConstant.PROPERTIES, properties);

        JSONArray blocks = new JSONArray();
        blocks.add(blockJson);

        JSONObject payload = new JSONObject();
        payload.put(IotKeyConstant.BLOCKS, blocks);

        String traceId = IdWorker.get32UUID();
        Date nowDate = DateUtils.getNowDate();
        String propertySetTopic = SysTopics.PROPERTY_SET
            .replace("${productKey}", device.getProductKey())
            .replace("${deviceSn}", device.getDeviceSn());

        sendMessage(device, traceId, propertySetTopic, payload.toJSONString(), nowDate);
    }


    private void sendMessage(DeviceEntity device, String traceId, String topic, String payload, Date nowDate) {
        log.info("调用接口给设备发送消息，traceId={}，deviceId={}，topic={}，message={}", traceId, device.getId(), topic, payload);
        remoteMqttService.sendMessageToDevice(traceId, device.getProductKey(), device.getDeviceSn(), topic, payload);

        DeviceInfo deviceInfo = new DeviceInfo(
            device.getTenantId(),
            device.getProductId(),
            device.getProductKey(),
            device.getId(),
            device.getDeviceSn(),
            device.getDataType()
        );

        IotMqttMessage mqttMessage = new IotMqttMessage(
            traceId,
            topic,
            payload,
            MqttQoS.AT_MOST_ONCE.value(),
            device.getDataType(),
            nowDate
        );
        deviceLogService.saveDeviceLogToTD(deviceInfo, mqttMessage, BizLogType.downLink, BizLogCode.SUCCESS);
    }

}
